package com.gitee.sxran.dynagraphql;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;


import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;

/**
 * 动态graphQHL的实现。
 * 其他的可以实现execPath
 * 默认同步.
 */
public abstract class DynGraphqlResolver {
    public static final Log log = LogFactory.get();
    protected final JSONArray jsonArray;
    protected final JSONObject resultJson;
    protected final int size;
    /**
     * @param json 数组
     */
    public DynGraphqlResolver(JSONArray json) {
        this.jsonArray = json;
        this.size = jsonArray.size();
        this.resultJson = new JSONObject(size);
    }


    /**
     * 执行Graph处理
     * @return 结果集
     * @throws Exception
     */
    public final JSONObject run() throws Exception {
        // 最外层遍历。
        for (int i = 0; i < this.size ; i++) {
            JSONObject jsonObject = this.jsonArray.getJSONObject(i);
            // 存放的name
            String asName = jsonObject.getStr("~name", null);
            asName = StrUtil.isBlank(asName) ? ""+i : asName;
            Object result = execAction(jsonObject,asName);
            // 如果有就不存放了。
            this.resultJson.putIfAbsent(asName,result);
        }

        this.destroy();

        return this.resultJson;

    }


    public final JSONObject getResultJson() {
        return resultJson;
    }


    /**
     * 执行销毁
     */
    public void destroy(){};


    /**
     * 执行数组中的一个行动。
     * @param jsonObject 单个入参.
     * @param asName 放到结果集中的内容
     * @return
     * @throws Exception
     */
    public Object execAction(JSONObject jsonObject,String asName) throws Exception {

        // 开始组装数据
        Set<Map.Entry<String, Object>> entries = jsonObject.entrySet();

        // 执行代码的路径
        String path = jsonObject.getStr("~path", null);
        path = StrUtil.isBlank(path) ? asName : path;

        // 参数.
        JSONObject argJson = new JSONObject();
        //
        JSONObject alisJson = new JSONObject();
        JSONObject subJson = new JSONObject();
        //
        for (Map.Entry<String, Object> entry : entries) {
            String name = entry.getKey();
            Object value = entry.getValue();

            String subSuf = StrUtil.subSuf(name, 1);

            if( StrUtil.startWith( name,'!') ){ // 固定参数.就不管他.
                argJson.putIfAbsent(subSuf, value);
            }else if( StrUtil.startWith( name,'@') ){ // 动态获得参数,从arraJson中获得.
                String expression = String.valueOf(value);
                // 从整个列表里面获得内容.
                Object byPath = this.jsonArray.getByPath(expression);
                argJson.putIfAbsent(subSuf, byPath);
            }else if(StrUtil.startWith( name,'#')){ // 嵌套方法.
                // 递归调用方法.
                JSONObject subJSONObject = jsonObject.getJSONObject(name);
                // 先执行里层的。
                Object subResult = this.execAction(subJSONObject, subSuf);
                argJson.putIfAbsent(subSuf, subResult);
                subJson.putIfAbsent(subSuf, subResult);
            }else if ( StrUtil.startWith( name,'~') ) {
                // 系统规范必须要的内容. 不做处理.
            }else if ( StrUtil.startWith( name,'$') ) {

                /*
                String resultAsName =  StrUtil.subBefore(expression, '.', false);
                Future<Object> future = this.threadMap.get(resultAsName);
                if(future == null)
                    throw new NullPointerException(StrUtil.format("${}=[{}],resultAsName=[{}] not exsits",subSuf,expression,resultAsName));
                threadList.add(asName);
                // 阻塞.
                future.get();*/
                Object byPath = this.getValueByPathForResult(value);
                argJson.putIfAbsent(subSuf, byPath);
            }else { // 其他的就都是 别名或者说结果字段.
                alisJson.putIfAbsent(name,value);
            }
            //
        }
        // 执行结果
        Object result = execPath(path,argJson,alisJson,subJson);
        return result;
    }

    /**
     * $开头的参数
     * 从其他结果集中获得内容.
     * @param value
     * @return
     */
    public Object getValueByPathForResult(Object value) throws ExecutionException, InterruptedException {
        // 从其他结果集中获得内容.
        String expression = String.valueOf(value);
        // 从结果里面取值
        Object byPath = this.resultJson.getByPath(expression);
        return byPath;
        
    }


    /**
     * 从execAction中整理的内容,下放到子类具体实现。
     * @param path 路径.
     * @param argJson 参数.
     * @param alisJson 别名.
     * @param subJson 子集嵌套.
     * @return
     */
    public abstract Object execPath(String path , JSONObject argJson, JSONObject alisJson, JSONObject subJson);

}
